﻿import type {RequestOptions} from '@@/plugin-request/request';
import type {RequestConfig} from '@umijs/max';
import {message} from 'antd';
import moment from "moment";
import {history} from "@@/core/history";
import {stringify} from "querystring";
import {AxiosResponse} from "axios";

// 错误处理方案： 错误类型
enum ErrorShowType {
  SILENT = 0,
  WARN_MESSAGE = 1,
  ERROR_MESSAGE = 2,
  NOTIFICATION = 3,
  REDIRECT = 9,
}
// 与后端约定的响应数据格式
interface ResponseStructure {
  success: boolean;
  data: any;
  errorCode?: number;
  errorMessage?: string;
  showType?: ErrorShowType;
}

enum FileSuffixType {
  ZIP = '.zip',
  JSON = '.json',
  GIF = '.gif',
  XLS = '.xls',
  XLSX = '.xlsx',
}

enum HttpCode  {
  '请求错误' = 400,
  '未授权' = 401,
  '禁止访问' = 403,
  '未找到服务' = 404,
  '链接过多' = 429,
  '服务器异常'= 500,
  '服务未实现' = 501,
  '网关异常' = 502,
  '服务不可用' = 503,
  '网关超时' = 504,
}

interface Response<T = any> extends AxiosResponse<T> {
  total?: number;
  success?: boolean;
  headers: {
    'X-Total-Count'?: number;
    'x-total-count'?: number;
    totalCount?: number;
    [propName: string]: any;
  };
}

function isSupport(suffix: string): boolean {
  for (const sElement of Object.values(FileSuffixType).toString()) {
    if (suffix.indexOf(sElement) !== -1) {
      return true;
    }
  }
  return false;
}


function handlerResponse(response: Response){
  const {status, data} = response;
  if (response.config.responseType === 'blob') {
    const contentDisposition = response.headers['content-disposition'] || '';
    const [type, fileNameStr] = contentDisposition.split(';');

    if (type === 'attachment' && isSupport(fileNameStr)) {
      let fileName = fileNameStr.split('=')[1] || '下载文件';
      fileName = decodeURIComponent(fileName);
      try {
        const blob = new Blob([data]);
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.setAttribute('href', url);
        link.setAttribute('download', fileName);
        link.style.display = 'none';
        document.body.appendChild(link);
        link.click();
        URL.revokeObjectURL(url); // 释放URL 对象
        document.body.removeChild(link);
      } catch (e) {
        //
      }
      if (status !== 200 && status !== 201 && status !== 401) {
        message.error(`${data?.msg || HttpCode[status] || '系统异常'} `);
        return;
      }
      return;
    }

    const fr = new FileReader();
    fr.onloadend = () => {
      try {
        const msg = JSON.parse(fr.result as string);
        message.error(msg.message);
      } catch (e) {
        //
      }
    };
    fr.readAsText(data);
    return;
  }
  if ((status !== 200 && status !== 201 && status !== 401)
    || (status === 200 && data && data.code !== 200)) {
    message.error(`${data?.msg || HttpCode[status] || '系统异常'}`);
    return;
  }
  // override response data
  response['data'] = {
    ...data,
    total: Number(response?.headers?.['x-total-count']),
    next: response?.headers?.['x-page-next'],
    skip: response?.headers?.['x-page-skip'],
  };
}

/**
 * @name 错误处理
 * pro 自带的错误处理， 可以在这里做自己的改动
 * @doc https://umijs.org/docs/max/request#配置
 */
export const errorConfig: RequestConfig = {
  // 错误处理： umi@3 的错误处理方案。
  errorConfig: {
    // 错误抛出
    errorThrower: (res) => {
      const {  data, code, msg } =
        res as unknown as API.RestResponse;
      if (code !== 200) {
        const error: any = new Error(msg);
        error.name = 'BizError';
        error.info = { msg, data };
        throw error; // 抛出自制的错误
      }
    },
    // 错误接收及处理
    errorHandler: (error: any, opts: any) => {
      if (opts?.skipErrorHandler) throw error;
      // 我们的 errorThrower 抛出的错误。
      const data = error?.response?.data
      const status = error?.response?.status
      if (error.name === 'BizError') {
        const errorInfo: API.RestResponse | undefined = error?.info;
        if (errorInfo) {
          const { msg } = errorInfo;
          message.error(msg);
        }
      } else if (error.response) {
        // Axios 的错误
        // 请求成功发出且服务器也响应了状态码，但状态代码超出了 2xx 的范围
        message.error(`${data?.msg || HttpCode[status] || '服务异常'}`);
      } else if (error.request) {
        // 请求已经成功发起，但没有收到响应
        // \`error.request\` 在浏览器中是 XMLHttpRequest 的实例，
        // 而在node.js中是 http.ClientRequest 的实例
        message.error('没有返回，请重试！');
      } else {
        // 发送请求时出了点问题
        message.error('请求错误，请重试！');
      }

    },
  },

  // 请求拦截器
  requestInterceptors: [
    (config: RequestOptions) => {
      // 拦截请求配置，进行个性化处理。
      const headers =  {'X-Front-Trade-Id': `${moment().unix()}${Math.floor(Math.random() * 1000)}}`, ...(config.headers || {})}
      return { headers:headers,...config};
    },
  ],

  // 响应拦截器
  responseInterceptors: [
    (response) => {
      // 拦截响应数据，进行个性化处理
      if (response.status >= 200 && response.status < 300) {
        return response;
      }
      // unauthorized
      if ([401].includes(response.status)) {
        // 跳转到登录页
        const { search, pathname } = window.location;
        /** 此方法会跳转到 redirect 参数所在的位置 */
        const urlParams = new URL(window.location.href).searchParams;
        const redirect = urlParams.get('redirect');
        if (window.location.pathname !== '/user/login' && !redirect) {
          history.replace({
            pathname: '/user/login',
            search: stringify({
              redirect: pathname + search,
            }),
          });
        }
        return response;
      }
      // override data
      handlerResponse(response);
      return response;
    },
  ],
};
